package com.gw.booking.service;

import com.google.common.collect.Lists;
import com.gw.booking.common.*;
import com.gw.booking.dto.PageDto;
import com.gw.booking.dto.backend.*;
import com.gw.booking.dto.wechat.*;
import com.gw.booking.entity.*;
import com.gw.booking.redis.RedisManage;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class OrderService {

    @Autowired
    private SessionFactory sessionFactory;
    @Autowired
    private RandomNumberService randomNumberService;
    @Autowired
    private LogService logService;
    @Autowired
    private AccessTokenService accessTokenService;
    @Autowired
    private OrderFormService orderFormService;
    @Autowired
    private MerchantService merchantService;
    @Autowired
    private MerchantTypeService merchantTypeService;
    @Autowired
    private OrderTimeService orderTimeService;

    /**
     * 订单列表（后台）
     *
     * @param shopName
     * @param orderCode
     * @param name
     * @param state
     * @param beginDate
     * @param endDate
     * @param wechat
     * @param page
     * @param size
     * @return
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    public PageDto<OrderListDtoOut> list(String shopName, String orderCode, String name, Integer state
            , String beginDate, String endDate, Integer wechat, Integer merchantTypeId, int page, int size, LoginToken loginToken)
            throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, ParseException {
        Session session = sessionFactory.getCurrentSession();
        Map<String, Object> params = new HashMap<>();
        params.put("state", state);
        params.put("cityId", loginToken.getCityId());
        String sqlCount = " select count(*) from orders o inner join merchant m on  o.merchant_id = m.id " +
                " inner join merchant_type mt on m.merchant_type_id = mt.id " +
                " left join discount d on o.discount_id = d.id ";
        String sql = " select o.id as orderId, o.order_code as orderCode, m.id as merchantId, " +
                " m.shop_name as shopName, m.merchant_type_id as merchantTypeId, mt.type_name as merchantTypeName, " +
                " o.state as state, o.name as name, " +
                " o.phone as phone, o.order_num as orderNum, o.order_date as orderDate, " +
                " o.order_time as orderTime, d.id as discountId,o.note from orders o " +
                " inner join merchant m on  o.merchant_id = m.id " +
                " inner join merchant_type mt on m.merchant_type_id = mt.id " +
                " left join discount d on d.id = o.discount_id ";
        String sqlWhere = " where 1 = 1 and o.state = :state and m.city_id = :cityId ";
        String sqlOrder = " order by o.created_at desc, o.order_date  desc,DATE_FORMAT(o.order_time,'%T') desc  ";
        if (wechat != null) {
            if (0 == wechat) {
                sqlWhere += " and m.open_id is not null ";
            } else if (1 == wechat) {
                sqlWhere += " and m.open_id is null  ";
            }
        }
        if (!StringUtils.isBlank(shopName)) {
            params.put("shopName", "%" + shopName + "%");
            sqlWhere += " and m.shop_name like :shopName ";
        }
        if (!StringUtils.isBlank(orderCode)) {
            params.put("orderCode", "%" + orderCode + "%");
            sqlWhere += " and o.order_code like :orderCode ";
        }
        if (!StringUtils.isBlank(name)) {
            params.put("name", "%" + name + "%");
            sqlWhere += " and o.name like :name ";
        }
        if (merchantTypeId != null) {
            params.put("merchantTypeId", merchantTypeId);
            sqlWhere += " and m.merchant_type_id = :merchantTypeId ";
        }

        if (!StringUtils.isBlank(beginDate) && !StringUtils.isBlank(endDate)) {
            DateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
            params.put("beginDate", sf.parse(beginDate));
            params.put("endDate", sf.parse(endDate));
            sqlWhere += " and o.order_date >= :beginDate " +
                    "  and o.order_date <= :endDate ";
        }

        BigInteger total = (BigInteger) session.createSQLQuery(sqlCount + sqlWhere)
                .setProperties(params)
                .uniqueResult();
        List<OrderListDtoOut> items = session.createSQLQuery(sql + sqlWhere + sqlOrder)
                .setProperties(params)
                .setResultTransformer(Transformers.aliasToBean(OrderListDtoOut.class))
                .setFirstResult(Util.calFirst(page, size))
                .setMaxResults(size)
                .list();
        for (OrderListDtoOut orderListDtoOut : items) {
            orderListDtoOut.setOrderTimeDtoList(orderTimeService.getOrderTimeList(session, orderListDtoOut.getOrderId()));
        }
        return new PageDto(page, size, total.longValue(), items);
    }

    /**
     * 预约详情（后台）
     *
     * @param orderId
     * @return
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    public OrderDetailDtoOut detail(Integer orderId, LoginToken loginToken) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Session session = sessionFactory.getCurrentSession();
        String sql = " select o.id as orderId, o.order_code as orderCode, m.id as merchantId, " +
                " m.shop_name as shopName, o.state as state, o.name as name, " +
                " o.phone as phone, o.order_num as orderNum, o.order_date as orderDate, " +
                " o.order_time as orderTime, d.id as discountId, o.note, mt.id as merchantTypeId, " +
                " mt.type_name as merchantTypeName, mt.order_time_num as orderTimeNum," +
                " o.fail_reason as failReason, o.fail_note as failNote " +
                " from orders o " +
                " inner join merchant m on  o.merchant_id = m.id" +
                " inner join merchant_type mt on m.merchant_type_id = mt.id  " +
                " left join discount d on d.id = o.discount_id " +
                " where 1 = 1 and o.id = :orderId and m.city_id = :cityId ";
        OrderDetailDtoOut orderDetailDtoOut = (OrderDetailDtoOut) session.createSQLQuery(sql)
                .setParameter("orderId", orderId)
                .setParameter("cityId", loginToken.getCityId())
                .setResultTransformer(Transformers.aliasToBean(OrderDetailDtoOut.class))
                .uniqueResult();
        orderDetailDtoOut.setOrderTimeDtoList(orderTimeService.getOrderTimeList(session, orderId));
        return orderDetailDtoOut;
    }

    /**
     * 预约编辑（后台）
     *
     * @param dto
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    public void txUpdate(LoginToken loginToken, OrderDetailDto dto) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Session session = sessionFactory.getCurrentSession();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Timestamp ts = new Timestamp(System.currentTimeMillis());
        //检查订单状态
        Orders orders = (Orders) session.get(Orders.class, dto.getOrderId());
        if (orders == null) {
            throw new ApiException(MessageCode.CODE_ORDER_NOT_EXISTS);
        }
        if (!dto.getState().equals(orders.getState())) {
            checkOrderState(orders.getState(), dto.getState());
        }
        //检查订单合理性
        Merchant merchant = (Merchant) session.get(Merchant.class, orders.getMerchantId());
        if (merchant == null) {
            throw new ApiException(MessageCode.CODE_MERCHANT_NOT_EXISTS);
        }
        if (!loginToken.getCityId().equals(merchant.getCityId())) {
            throw new ApiException(MessageCode.CODE_NO_PRIVILEGE);
        }
        Customer customer = (Customer) session.get(Customer.class, orders.getCustomerId());
        if (customer == null) {
            throw new ApiException(MessageCode.CODE_CUSTOMER_NOT_EXISTS);
        }


        //修改数据库
        SimpleDateFormat sdf1 = new SimpleDateFormat("HH:mm");
        String orderDateOld;
        //如果是确认前的订单修改则可以修改订单时间集合,否则只能修改预约时间
        if (orders.getOrderTime() != null
                || orders.getOrderDate() != null
                || dto.getOrderDate() != null
                || dto.getOrderTime() != null) {
            String orderDate = orders.getOrderDate() == null ? "" : sdf.format(orders.getOrderDate());
            String orderTime = orders.getOrderTime() == null ? "" : sdf1.format(orders.getOrderTime());
            orderDateOld = orderDate + " " + orderTime;
            orders.setOrderDate(dto.getOrderDate());
            orders.setOrderTime(new Timestamp(dto.getOrderTime().getTime()));
        } else {
            List<OrderTimeDto> orderTimeDtoList = orderTimeService.getOrderTimeList(session, orders.getId());
            orderDateOld = "";
            for (int i = 0; i < orderTimeDtoList.size(); i++) {
                if (i == 0) {
                    orderDateOld += sdf.format(orderTimeDtoList.get(i).getOrderDate()) + " " + sdf1.format(orderTimeDtoList.get(i).getOrderTime());
                }
            }
            //修改订单时间集合
            orderTimeService.txAddOrderTimes(session, dto.getOrderTimeDtoList(), orders.getId());
        }
        orders.setName(dto.getName());
        orders.setPhone(dto.getPhone());
        orders.setOrderNum(dto.getOrderNum());

        //却下订单填入却下理由和备注
        if (dto.getState().equals(Constant.ORDER_STATUS_FAIL)) {
            orders.setFailReason(dto.getFailReason());
            orders.setFailNote(dto.getFailNote());
        }
        orders.setState(dto.getState());
        orders.setNote(dto.getNote());
        orders.setUpdatedAt(ts);
        session.save(orders);
        session.flush();


        logService.txAddLog(Logs.LogType.edit, loginToken.getUserId(), "编辑预约：" + orders.getId());


        //发送推送
        //预约确认和预约取消推送sendSmsForDiner
        //否则为订单内容修改操作推送sendSmsForDinerChange
        if (dto.getState().equals(Constant.ORDER_STATUS_CONFIRM) || dto.getState().equals(Constant.ORDER_STATUS_FAIL)) {
            sendMsgForDiner(dto.getState(), dto.getFailReason(), orders.getId(), customer.getOpenId(), orders.getName(),
                    merchant.getShopName(), sdf.format(orders.getOrderDate()) + " " + sdf1.format(orders.getOrderTime()));
        } else {
            sendSmsForDinerChange(customer.getOpenId(), orders.getId() + "", orders.getName()
                    , orderDateOld, merchant.getShopName());
        }

    }

    /**
     * 预约列表（商家）
     *
     * @param loginToken
     * @param orderDate
     * @param state
     * @param page
     * @param size
     * @return
     */
    public PageDto<WMerchantOrderListDtoOut> listForMerchant(LoginToken loginToken, String orderDate, Integer state, int page, int size) throws ParseException {
        if (!Constant.USER_TYPE_MERCHANT.equals(loginToken.getType())) {
            throw new ApiException(MessageCode.CODE_NO_PRIVILEGE);
        }
        Session session = sessionFactory.getCurrentSession();
        Map<String, Object> params = new HashMap<>();
        params.put("merchantId", loginToken.getUserId());
        params.put("state", state);

        String sql = " select o.id as id ,o.name as name,o.order_num as orderNum,o.order_date as orderDate," +
                " o.order_time as orderTime,o.state as state " +
                " from orders o inner join customer c on o.customer_id = c.id " +
                " left join order_time ot on o.id = ot.order_id ";
        String sqlWhere = " where 1 = 1 and o.merchant_id = :merchantId ";
        String sqlOrder = " order by case when o.state = 0 then 1 else 0 end desc, o.created_at desc,o.order_date  desc,DATE_FORMAT(o.order_time,'%T') desc  ";
        String sqlGroupBy = " group by o.id ,o.name ,o.order_num ,o.order_date,o.order_time ,o.state ";
        if (state != null) {
            //如果state=0则无视传入时间，查询预约时间包含今天及以后的数据
            if (state.equals(Constant.ORDER_STATUS_HANDING)) {
                sqlWhere += " and o.state = :state and ot.order_date >= :orderDate ";
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                params.put("orderDate", sdf.parse(sdf.format(new Date())));
            } else {
                sqlWhere += " and o.state = :state ";
                if (StringUtils.isNotBlank(orderDate)) {
                    sqlWhere += " and o.order_date = :orderDate ";
                    params.put("orderDate", orderDate);
                }
            }
        } else {
            if (StringUtils.isNotBlank(orderDate)) {
                sqlWhere += " and (o.order_date = :orderDate or o.state = 0)";
                params.put("orderDate", orderDate);
            }
        }
        String sqlCount = "select count(*) from ( " + sql + sqlWhere + sqlGroupBy + " ) a";
        BigInteger total = (BigInteger) session.createSQLQuery(sqlCount)
                .setProperties(params)
                .uniqueResult();
        List<WMerchantOrderListDtoOut> items = session.createSQLQuery(sql + sqlWhere + sqlGroupBy + sqlOrder)
                .setProperties(params)
                .setResultTransformer(Transformers.aliasToBean(WMerchantOrderListDtoOut.class))
                .setFirstResult(Util.calFirst(page, size))
                .setMaxResults(size)
                .list();
        for (WMerchantOrderListDtoOut wMerchantOrderListDtoOut : items) {
            wMerchantOrderListDtoOut.setOrderTimeDtoList(orderTimeService.getOrderTimeList(session, wMerchantOrderListDtoOut.getId()));
        }
        return new PageDto(page, size, total.longValue(), items);
    }

    /**
     * 预约详情（商家）
     *
     * @param loginToken
     * @param orderId
     * @return
     */
    public WOrderDetailDtoOut detailForMerchant(LoginToken loginToken, Integer orderId) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Session session = sessionFactory.getCurrentSession();
        Orders orders = (Orders) session.get(Orders.class, orderId);
        if (orders == null) {
            throw new ApiException(MessageCode.CODE_ORDER_NOT_EXISTS);
        }
        if (!orders.getMerchantId().equals(loginToken.getUserId())) {
            throw new ApiException(MessageCode.CODE_NO_PRIVILEGE);
        }
        WOrderDetailDtoOut wOrderDetailDtoOut = new WOrderDetailDtoOut();
        PropertyUtils.copyProperties(wOrderDetailDtoOut, orders);
        //获取预约时间信息
        List<OrderTimeDto> orderTimeDtoList = orderTimeService.getOrderTimeList(session, orderId);
        wOrderDetailDtoOut.setOrderTimeDtoList(orderTimeDtoList);
        //获取商家信息
        Merchant merchant = (Merchant) session.get(Merchant.class, orders.getMerchantId());
        WMerchantDo wMerchantDo = new WMerchantDo();
        PropertyUtils.copyProperties(wMerchantDo, merchant);
        wOrderDetailDtoOut.setwMerchantDo(wMerchantDo);
        //获取优惠信息
        if (orders.getDiscountId() != null) {
            Discount discount = (Discount) session.get(Discount.class, orders.getDiscountId());
            WDIscountDtoOut wdIscountDtoOut = new WDIscountDtoOut();
            PropertyUtils.copyProperties(wdIscountDtoOut, discount);
            wOrderDetailDtoOut.setWdIscountDtoOut(wdIscountDtoOut);
        }
        return wOrderDetailDtoOut;
    }

    /**
     * 修改订单状态
     *
     * @param loginToken
     * @param dto
     */
    public void txUpdateByMerchant(LoginToken loginToken, WMerchantOrderDto dto) {
        Session session = sessionFactory.getCurrentSession();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sdf1 = new SimpleDateFormat("HH:mm:ss");
        //确认订单状态
        Orders orders = (Orders) session.get(Orders.class, dto.getOrderId());
        if (orders == null) {
            throw new ApiException(MessageCode.CODE_ORDER_NOT_EXISTS);
        }
        checkOrderState(orders.getState(), dto.getState());
        //验证用户权限
        if (!loginToken.getType().equals(Constant.USER_TYPE_MERCHANT) || !loginToken.getUserId().equals(orders.getMerchantId())) {
            throw new ApiException(MessageCode.CODE_NO_PRIVILEGE);
        }
        //确认订单合理性
        Customer customer = (Customer) session.get(Customer.class, orders.getCustomerId());
        if (customer == null) {
            throw new ApiException(MessageCode.CODE_CUSTOMER_NOT_EXISTS);
        }
        Merchant merchant = merchantService.sureMerchant(session, orders.getMerchantId());
        //确认订单操作需确认预约时间
        if (orders.getState().equals(Constant.ORDER_STATUS_HANDING)
                && dto.getState().equals(Constant.ORDER_STATUS_CONFIRM)) {
            if (dto.getOrderDate() == null || dto.getOrderTime() == null) {
                throw new ApiException(MessageCode.CODE_NEED_ORDER_TIME_ERROR);
            }
            orders.setOrderDate(dto.getOrderDate());
            orders.setOrderTime(new Timestamp(dto.getOrderTime().getTime()));
        }

        //却下订单填入却下理由和备注
        if (dto.getState().equals(Constant.ORDER_STATUS_FAIL)) {
            orders.setFailReason(dto.getFailReason());
            orders.setFailNote(dto.getFailNote());
        }
        orders.setState(dto.getState());
        orders.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
        session.update(orders);
        session.flush();
        //商家推送给对应的用户

        if (dto.getState().equals(Constant.ORDER_STATUS_CONFIRM) || dto.getState().equals(Constant.ORDER_STATUS_FAIL)) {
            String orderDate = "";
            if (orders.getOrderDate() != null) {
                orderDate = sdf.format(orders.getOrderDate()) + " " + sdf1.format(orders.getOrderTime());
            } else {
                List<OrderTimeDto> orderTimeDtos = orderTimeService.getOrderTimeList(session, orders.getId());
                for (int i = 0; i < orderTimeDtos.size(); i++) {
                    if (i == 0) {
                        orderDate = sdf.format(orderTimeDtos.get(i).getOrderDate());
                    } else {
                        orderDate = "," + sdf.format(orderTimeDtos.get(i).getOrderDate());
                    }
                }
            }
            sendMsgForDiner(dto.getState(), dto.getFailReason(), orders.getId(), customer.getOpenId(), orders.getName(),
                    merchant.getShopName(), orderDate);
        }
    }

    /**
     * 修改订单内容(作废)
     *
     * @param loginToken
     * @param dto
     */
    public void txChangeByMerchant(LoginToken loginToken, WMerchantChangeOrderDto dto) {
        Session session = sessionFactory.getCurrentSession();
        Orders order = (Orders) session.get(Orders.class, dto.getOrderId());
        if (!order.getMerchantId().equals(loginToken.getUserId())) {
            throw new ApiException(MessageCode.CODE_NO_PRIVILEGE);
        }

        Customer customer = (Customer) session.get(Customer.class, order.getCustomerId());
        if (customer == null) {
            throw new ApiException(MessageCode.CODE_CUSTOMER_NOT_EXISTS);
        }
        Merchant merchant = (Merchant) session.get(Merchant.class, order.getMerchantId());

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sdf1 = new SimpleDateFormat("HH:mm");

        String orderDateOld;
        //订单时间确认后，只能修改预约时间，否则更换订单时间集合
        if (order.getOrderDate() != null || order.getOrderTime() != null) {
            orderDateOld = sdf.format(order.getOrderDate()) + " " + sdf1.format(order.getOrderTime());
            order.setOrderNum(dto.getOrderNum());
            order.setOrderDate(dto.getOrderDate());
            order.setOrderTime(new Timestamp(dto.getOrderTime().getTime()));
            order.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
            session.update(order);
            session.flush();
        } else {
            List<OrderTimeDto> orderTimeDtoList = orderTimeService.getOrderTimeList(session, order.getId());
            orderDateOld = "";
            for (int i = 0; i < orderTimeDtoList.size(); i++) {
                if (i == 0) {
                    orderDateOld += sdf.format(orderTimeDtoList.get(i).getOrderDate()) + " " + sdf1.format(orderTimeDtoList.get(i).getOrderTime());
                }
            }
            order.setOrderNum(dto.getOrderNum());
            order.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
            session.update(order);
            session.flush();
            //修改订单时间集合
            orderTimeService.txAddOrderTimes(session, dto.getOrderTimeDtoList(), order.getId());
        }
        sendSmsForDinerChange(customer.getOpenId(), order.getId() + "", order.getName()
                , orderDateOld, merchant.getShopName());

    }

    /**
     * 预约列表（客户）
     *
     * @param loginToken
     * @param state
     * @param page
     * @param size
     * @return
     */
    public PageDto<WOrderListDtoOut> listForDiner(LoginToken loginToken, Integer state, int page, int size) {
        Session session = sessionFactory.getCurrentSession();
        Map<String, Object> params = new HashMap<>();
        params.put("customerId", loginToken.getUserId());
        String sqlCount = "select count(*) from orders o inner join merchant m on o.merchant_id = m.id ";
        String sql = " select o.id as orderId, o.order_num as orderNum, " +
                " o.order_date as orderDate, o.order_time as orderTime, o.state as state, m.shop_name as shopName, " +
                " m.shop_img1 as shopImg1, m.shop_img2 as shopImg2, m.shop_img3 as shopImg3 " +
                " from orders o inner join merchant m on o.merchant_id = m.id ";
        String sqlWhere = " where 1 = 1 and o.customer_id = :customerId ";
        String sqlOrder = " order by o.created_at desc, o.order_date  desc,DATE_FORMAT(o.order_time,'%T') desc  ";
        if (state != null) {
//            sqlWhere += " and o.state in (:states) ";
//            List<Integer> states = Lists.newArrayList(state);
//            if (3 == state) {
//                states.add(4);
//            }
            sqlWhere += " and o.state = :state ";
            params.put("state", state);
        }
        BigInteger total = (BigInteger) session.createSQLQuery(sqlCount + sqlWhere)
                .setProperties(params)
                .uniqueResult();
        List<WOrderListDtoOut> items = session.createSQLQuery(sql + sqlWhere + sqlOrder)
                .setProperties(params)
                .setResultTransformer(Transformers.aliasToBean(WOrderListDtoOut.class))
                .setFirstResult(Util.calFirst(page, size))
                .setMaxResults(size)
                .list();
        for (WOrderListDtoOut wOrderListDtoOut : items) {
            wOrderListDtoOut.setOrderTimeDtoList(orderTimeService.getOrderTimeList(session, wOrderListDtoOut.getOrderId()));
        }
        return new PageDto(page, size, total.longValue(), items);
    }

    /**
     * 预约详情（客户）
     *
     * @param loginToken
     * @param orderId
     * @return
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    public WOrderDetailDtoOut detailForDiner(LoginToken loginToken, Integer orderId) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Session session = sessionFactory.getCurrentSession();
        Orders orders = (Orders) session.get(Orders.class, orderId);
        if (orders == null) {
            throw new ApiException(MessageCode.CODE_ORDER_NOT_EXISTS);
        }
        if (!orders.getCustomerId().equals(loginToken.getUserId())) {
            throw new ApiException(MessageCode.CODE_NO_PRIVILEGE);
        }
        WOrderDetailDtoOut wOrderDetailDtoOut = new WOrderDetailDtoOut();
        PropertyUtils.copyProperties(wOrderDetailDtoOut, orders);
        //获取预约时间信息
        List<OrderTimeDto> orderTimeDtoList = orderTimeService.getOrderTimeList(session, orderId);
        wOrderDetailDtoOut.setOrderTimeDtoList(orderTimeDtoList);
        //获取商家信息
        Merchant merchant = (Merchant) session.get(Merchant.class, orders.getMerchantId());
        MerchantType merchantType = merchantTypeService.sureMerchantType(session, merchant.getMerchantTypeId());
        WMerchantDo wMerchantDo = new WMerchantDo();
        PropertyUtils.copyProperties(wMerchantDo, merchant);
        wMerchantDo.setMerchantTypeName(merchantType.getTypeName());
        wMerchantDo.setOrderTimeNum(merchantType.getOrderTimeNum());
        wOrderDetailDtoOut.setwMerchantDo(wMerchantDo);
        //获取优惠信息
        if (orders.getDiscountId() != null) {
            Discount discount = (Discount) session.get(Discount.class, orders.getDiscountId());
            WDIscountDtoOut wdIscountDtoOut = new WDIscountDtoOut();
            PropertyUtils.copyProperties(wdIscountDtoOut, discount);
            wOrderDetailDtoOut.setWdIscountDtoOut(wdIscountDtoOut);
        }
        return wOrderDetailDtoOut;
    }

    /**
     * 取消预约（客户）
     *
     * @param loginToken
     * @param orderId
     */
    public void txUpdateByDiner(LoginToken loginToken, Integer orderId) {
        Session session = sessionFactory.getCurrentSession();
        Orders order = (Orders) session.get(Orders.class, orderId);
        if (order == null) {
            throw new ApiException(MessageCode.CODE_ORDER_NOT_EXISTS);
        }
        if (!order.getCustomerId().equals(loginToken.getUserId())) {
            throw new ApiException(MessageCode.CODE_NO_PRIVILEGE);
        }
        checkOrderState(order.getState(), Constant.ORDER_STATUS_CANCEL);
        order.setState(Constant.ORDER_STATUS_CANCEL);
        order.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
        session.update(order);
        session.flush();
    }

    /**
     * 编辑订单（客户）
     *
     * @param loginToken
     * @param dto
     */
    public void txChange(LoginToken loginToken, WChangeOrderDto dto) {
        Session session = sessionFactory.getCurrentSession();
        //确认订单状态
        Orders order = (Orders) session.get(Orders.class, dto.getOrderId());
        if (!order.getCustomerId().equals(loginToken.getUserId())) {
            throw new ApiException(MessageCode.CODE_NO_PRIVILEGE);
        }
        if (!order.getState().equals(Constant.ORDER_STATUS_HANDING) && !order.getState().equals(Constant.ORDER_STATUS_CONFIRM)) {
            throw new ApiException(MessageCode.CODE_ORDER_9108);
        }

        Merchant merchant = merchantService.sureMerchant(session, order.getMerchantId());

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //如果预约时间未确认或置空预约时间，则修改预约时间集合
        if (order.getOrderDate() != null || order.getOrderTime() != null || dto.getOrderDate() == null || dto.getOrderTime() == null) {
            orderTimeService.txAddOrderTimes(session, dto.getOrderTimeDtoList(), order.getId());
            order.setState(Constant.ORDER_STATUS_HANDING);
        }
//        else {
//            //检查预约时间是否被修改
//            if (!sdf.format(order.getOrderDate()).equals(sdf.format(dto.getOrderDate()))
//                    || !sdf.format(new Date(order.getOrderTime().getTime())).equals(sdf.format(dto.getOrderTime()))) {
//                order.setState(Constant.ORDER_STATUS_HANDING);
//                order.setOrderDate(dto.getOrderDate());
//                order.setOrderTime(new Timestamp(dto.getOrderTime().getTime()));
//            }
//        }
        order.setDiscountId(dto.getDiscountId());
        order.setOrderNum(dto.getOrderNum());
        order.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
        order.setName(dto.getName());
        order.setPhone(dto.getPhone());
        order.setNote(dto.getNote());
        session.update(order);

        //用户推送给需确认的商家

        String msg;
        if (order.getDiscountId() != null) {
            Discount discount = (Discount) session.get(Discount.class, order.getDiscountId());
            msg = "特典：" + discount.getContentJ();
        } else {
            msg = "特典：无";
        }

        String orderDate = "";
        if (order.getOrderDate() != null) {
            orderDate = sdf.format(order.getOrderDate());
        } else {
            for (int i = 0; i < dto.getOrderTimeDtoList().size(); i++) {
                if (i == 0) {
                    orderDate += sdf.format(dto.getOrderTimeDtoList().get(i).getOrderDate());
                } else {
                    orderDate += "," + sdf.format(dto.getOrderTimeDtoList().get(i).getOrderDate());
                }
            }
        }
        String url = Constant.SEND_SMS_URL + order.getId();
        WXAppletUserInfo.sendSmsForMerchantChange(merchant.getOpenId(),
                accessTokenService.txGetAccessToken(Constant.USER_TYPE_MERCHANT),
                orderDate, order.getPhone(), msg, url, order.getName());
        session.flush();
    }

    /**
     * 新增预定（客户）
     *
     * @param loginToken
     * @param wOrderDto
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    public void txAdd(LoginToken loginToken, WOrderDto wOrderDto) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //检查订单电话10min内不重复下单
        String phone = RedisManage.getData(wOrderDto.getPhone());
        if (phone == null) {
            RedisManage.setData(wOrderDto.getPhone(), "1", 60 * 10);
        } else {
            throw new ApiException(MessageCode.CODE_ORDER_TOO_FREQUENT);
        }
        Session session = sessionFactory.getCurrentSession();
        //检查商家及类型数量限制
        Merchant merchant = merchantService.sureMerchant(session, wOrderDto.getMerchantId());
        MerchantType merchantType = merchantTypeService.sureMerchantType(session, merchant.getMerchantTypeId());
        if (merchantType.getOrderTimeNum() < wOrderDto.getOrderTimeDtoList().size()) {
            throw new ApiException(MessageCode.CODE_ORDER_TIME_ERROR);
        }

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Orders orders = new Orders();
        String orderCode = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + randomNumberService.getRandomNumber(session, "B");

        if (wOrderDto.getDiscountId() != null) {
            Discount discount = (Discount) session.get(Discount.class, wOrderDto.getDiscountId());
            if (discount == null) {
                throw new ApiException(MessageCode.CODE_DISCOUNT_NOT_EXISTS);
            }
            orders.setDiscountId(wOrderDto.getDiscountId());
        }
        orders.setOrderCode(orderCode);
        orders.setMerchantId(wOrderDto.getMerchantId());
        orders.setOrderNum(wOrderDto.getOrderNum());
        orders.setCustomerId(loginToken.getUserId());
        orders.setName(wOrderDto.getName());
        orders.setPhone(wOrderDto.getPhone());
        orders.setCreatedAt(new Timestamp(System.currentTimeMillis()));
        orders.setState(Constant.ORDER_STATUS_HANDING);
        orders.setNote(wOrderDto.getNote());
        session.save(orders);

        //添加预约时间
        orderTimeService.txAddOrderTimes(session, wOrderDto.getOrderTimeDtoList(), orders.getId());
        //添加formId
        for (String formId : wOrderDto.getFormIds()) {
            OrderForm orderForm = new OrderForm();
            orderForm.setOrderId(orders.getId());
            orderForm.setFormId(formId);
            orderForm.setCreatedAt(new Timestamp(System.currentTimeMillis()));
            session.save(orderForm);
        }

        //用户推送给需确认的商家
        String msg;
        if (orders.getDiscountId() != null) {
            Discount discount = (Discount) session.get(Discount.class, orders.getDiscountId());
            msg = "特典：" + discount.getContentJ();
        } else {
            msg = "特典：无";
        }
        String url = Constant.SEND_SMS_URL + orders.getId();
        //拼接订单日期
        String orderDate = "";
        for (int i = 0; i < wOrderDto.getOrderTimeDtoList().size(); i++) {
            if (i == 0) {
                orderDate += sdf.format(wOrderDto.getOrderTimeDtoList().get(i).getOrderDate());
            } else {
                orderDate += "," + sdf.format(wOrderDto.getOrderTimeDtoList().get(i).getOrderDate());
            }
        }
        WXAppletUserInfo.sendSmsForMerchant(merchant.getOpenId(), accessTokenService.txGetAccessToken(Constant.USER_TYPE_MERCHANT),
                orderDate, orders.getPhone(), msg, url, orders.getName());
        session.flush();
    }


    public void checkOrderState(Integer stateOld, Integer stateNew) {
        switch (stateNew) {
            case 1:
                if (!stateOld.equals(Constant.ORDER_STATUS_HANDING)) {
                    throw new ApiException(MessageCode.CODE_ORDER_9108);
                }
                break;
            case 2:
                if (!stateOld.equals(Constant.ORDER_STATUS_CONFIRM)) {
                    throw new ApiException(MessageCode.CODE_ORDER_9108);
                }
                break;
            case 3:
                if (!stateOld.equals(Constant.ORDER_STATUS_HANDING) && !stateOld.equals(Constant.ORDER_STATUS_CONFIRM)) {
                    throw new ApiException(MessageCode.CODE_ORDER_9108);
                }
                break;
            case 4:
                if (!stateOld.equals(Constant.ORDER_STATUS_HANDING) && !stateOld.equals(Constant.ORDER_STATUS_CONFIRM)) {
                    throw new ApiException(MessageCode.CODE_ORDER_9108);
                }
                break;
            default:
                throw new ApiException(MessageCode.CODE_ORDER_9108);

        }
    }


    public void txAutoUpdate() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sdf1 = new SimpleDateFormat("HH:mm:ss");
        Session session = sessionFactory.getCurrentSession();
        String sql = "select id from  `orders`  where state = 0" +
                " and (" +
                "   (DATE_FORMAT(created_at,'%H:%i:%S')>='00:00:00' and DATE_FORMAT(created_at,'%H:%i:%S')<='06:00:00' and" +
                "     TIMESTAMPDIFF(MINUTE, created_at, :time) >= 18*60 )" +
                "   or" +
                "   ( DATE_FORMAT(created_at,'%H:%i:%S')>'06:00:00' and " +
                "     TIMESTAMPDIFF(MINUTE, created_at, :time) >= 12*60 )" +
                " )";
        List<Integer> items = session.createSQLQuery(sql)
                .setParameter("time", new Date())
                .list();
        for(Integer id : items){
            Orders orders = (Orders) session.get(Orders.class, id);
            if (orders == null) {
               continue;
            }
            orders.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
            orders.setState(Constant.ORDER_STATUS_OVERTIME);
            session.saveOrUpdate(orders);
            Customer customer = (Customer) session.get(Customer.class, orders.getCustomerId());
            if (customer == null) {
                continue;
            }
            Merchant merchant = (Merchant) session.get(Merchant.class,  orders.getMerchantId());
            if (merchant == null) {
                continue;
            }
            String orderDate = "";
            if (orders.getOrderDate() != null) {
                orderDate = sdf.format(orders.getOrderDate()) + " " + sdf1.format(orders.getOrderTime());
            } else {
                List<OrderTimeDto> orderTimeDtos = orderTimeService.getOrderTimeList(session, orders.getId());
                for (int i = 0; i < orderTimeDtos.size(); i++) {
                    if (i == 0) {
                        orderDate = sdf.format(orderTimeDtos.get(i).getOrderDate());
                    } else {
                        orderDate = "," + sdf.format(orderTimeDtos.get(i).getOrderDate());
                    }
                }
            }
            sendMsgForDiner(Constant.ORDER_STATUS_OVERTIME, null, orders.getId(), customer.getOpenId(), orders.getName(),
                    merchant.getShopName(), orderDate);
        }
    }

    //    public void sendMsgForDiner(Integer state, Integer failReason, Integer id, String openId, String shopName,
//                                String orderDate, String address) {
//        String templateId;
//        String msg = null;
//        if (state.equals(Constant.ORDER_STATUS_CONFIRM)) {
//            templateId = Constant.ORDER_CONFIRM_MODEL_ID;
//        } else {
//            templateId = Constant.ORDER_CANCEL_MODEL_ID;
//            if (failReason != null && failReason.equals(Constant.ORDER_FAIL_REASON_FULL)) {
//                msg = Constant.ORDER_FAIL_REASON_MSG_FULL;
//            } else if (failReason != null && failReason.equals(Constant.ORDER_FAIL_REASON_REST)) {
//                msg = Constant.ORDER_FAIL_REASON_MSG_REST;
//            } else if (failReason != null && failReason.equals(Constant.ORDER_FAIL_REASON_OTHERS)) {
//                msg = Constant.ORDER_FAIL_REASON_MSG_OTHERS;
//            } else {
//                msg = Constant.ORDER_CANCEL_MODEL_MSG;
//            }
//        }
//        String url = Constant.ORDER_WECHAT_URL + id;
//        String formId = orderFormService.txGetFormId(id);
//        WXAppletUserInfo.sendSmsForDiner(openId, accessTokenService.txGetAccessToken(Constant.USER_TYPE_DINER)
//                , templateId, formId, url, shopName, orderDate, address, msg);
//    }
    public void sendMsgForDiner(Integer state, Integer failReason, Integer id, String openId, String name, String shopName,
                                String orderDate) {
        String orderMsg = null;
        if (state.equals(Constant.ORDER_STATUS_CONFIRM)) {
            orderMsg = Constant.ORDER_MSG_CONFIRM;
        } else if (state.equals(Constant.ORDER_STATUS_OVERTIME)) {
            orderMsg = Constant.ORDER_MSG_OVERTIME;
        } else {
            orderMsg = Constant.ORDER_MSG_CANCEL;
            if (failReason != null && failReason.equals(Constant.ORDER_FAIL_REASON_FULL)) {
                orderMsg = orderMsg.replace("[reason]", Constant.ORDER_FAIL_REASON_MSG_FULL);
            } else if (failReason != null && failReason.equals(Constant.ORDER_FAIL_REASON_REST)) {
                orderMsg = orderMsg.replace("[reason]", Constant.ORDER_FAIL_REASON_MSG_REST);
            } else if (failReason != null && failReason.equals(Constant.ORDER_FAIL_REASON_OTHERS)) {
                orderMsg = orderMsg.replace("[reason]", Constant.ORDER_FAIL_REASON_MSG_OTHERS);
            } else {
                orderMsg = orderMsg.replace("[reason]", Constant.ORDER_FAIL_REASON_MSG_FULL);
            }
        }
        WXAppletUserInfo.sendSmsForDinner(openId, accessTokenService.txGetAccessToken(Constant.USER_TYPE_DINER)
                , Constant.ORDER_TEMPLATE_ID, Constant.ORDER_WECHAT_URL + id, name, orderDate, shopName, orderMsg);
    }

    public void sendSmsForDinerChange(String openId, String id, String name, String orderDate
            , String shopName) {
        WXAppletUserInfo.sendSmsForDinner(openId, accessTokenService.txGetAccessToken(Constant.USER_TYPE_DINER)
                , Constant.ORDER_TEMPLATE_ID, Constant.ORDER_WECHAT_URL + id, name, orderDate, shopName, Constant.ORDER_MSG_CHANGE);
    }

}
